with Ada.Strings.Maps.Constants;
with Ada.Strings.Fixed;

--with Website_Retrieval.Host_Address_Parser;

--
-- Website_Retrieval
--
--    Retrieve: download a URL using HTTP.
--
--    Parse_Host_Address: separate URL into protocol, host and any path or
--       query string.
--

package body Website_Retrieval is

   use GNAT.String_Split;

   SPLIT_SEPARATOR : constant String := "/";

   --
   -- Parse_Host_Address
   --
   --    Separate URL into protocol, host and any path or query string.
   --

   function Parse_Host( Host_Address : in Host_Address_Sub_Type;

         Address_Portion_Enum : Address_Portion := Address_Portion'Value(
            "Host"))

         return String is

      --
      -- Portions of host address divided by each '/'
      --    Example: http:, www.myhost.com, index.html
      --

      Split_Sub_Strings : Slice_Set;

   begin
      Create (
              S          => Split_Sub_Strings,
              From       => Host_Address_Type.To_String(Host_Address),
              Separators => SPLIT_SEPARATOR,
              Mode       => Multiple);

      -- seek http://

      if( Address_Portion_Enum = Address_Portion'Value("Protocol") )
      then

         return Get_Protocol( Split_Sub_Strings );

      elsif( Address_Portion_Enum = Address_Portion'Value("Host") )
      then

         return Get_Host( Split_Sub_Strings );

      elsif( Address_Portion_Enum = Address_Portion'Value("Path") )
      then

         return Get_Path( Split_Sub_Strings );

      else

         raise Invalid_Address_Portion;

      end if;


   end Parse_Host;


   --
   -- Get_Protocol
   --
   --    Example: find protocol used, return as 'http://' or 'https://'
   --

   function Get_Protocol( Host_Pieces : in Slice_Set ) return String is

      package Results_Type is new Limit_Str.Generic_Bounded_Length(

            PROTOCOL_MAX_LENGTH );

      Results : Results_Type.Bounded_String;

   begin

      if( GNAT.String_Split.Slice_Count( Host_Pieces ) < 1 ) then

         raise Protocol_Parse_Failure;

      end if;

      Results_Type.Append( Results, GNAT.String_Split.Slice(

                           Host_Pieces, Slice_Number(1) ) );

      -- add '//' to 'http:' as removed by split

      Results_Type.Append( Results, SPLIT_SEPARATOR );
      Results_Type.Append( Results, SPLIT_SEPARATOR );

      -- example: convert HTTP:// to http://

      return Ada.Strings.Fixed.Translate(

            Results_Type.To_String( Results ),

            Ada.Strings.Maps.Constants.Lower_Case_Map);

   end Get_Protocol;


   --
   -- Get_Host
   --
   --    Find domain, 'www.myhost.com'.
   --

   function Get_Host( Host_Pieces : in Slice_Set ) return String is

      package Results_Type is new Limit_Str.Generic_Bounded_Length(

            HOST_MAX_LENGTH );

      Results : Results_Type.Bounded_String;

   begin

      if( GNAT.String_Split.Slice_Count( Host_Pieces ) < 2

         or

          Slice( Host_Pieces, 2 )'Size < HOST_MIN_LENGTH ) then

         raise Host_Parse_Failure;

      end if;

      Results_Type.Append( Results, GNAT.String_Split.Slice(

                           Host_Pieces, Slice_Number(2) ) );

      return Results_Type.To_String( Results );

   end Get_Host;


   --
   -- Get_Path
   --
   --    Find any path or query string.
   --
   --    Returns empty String if none found.
   --

   function Get_Path( Host_Pieces : in Slice_Set ) return String is

      package Results_Type is new Limit_Str.Generic_Bounded_Length(

            HOST_MAX_LENGTH );

      Results : Results_Type.Bounded_String;

   begin

      if( Slice_Count( Host_Pieces ) < 3 ) then

         return "";

      end if;

      for ct in Integer range 3 .. Integer( Slice_Count( Host_Pieces )) loop

         declare

            Portion : constant String := GNAT.String_Split.Slice( Host_Pieces,

                  Slice_Number(ct) );

         begin

            Results_Type.Append( Results, Portion );

            -- append '/' to rebuild path after split operation

            if( ct < Integer(Slice_Count( Host_Pieces )) ) then

               Results_Type.Append( Results, SPLIT_SEPARATOR );

            end if;

         end;

      end loop;

      return Results_Type.To_String( Results );

   end Get_Path;


end Website_Retrieval;